#include "e2d/ui/SceneTreeNodeEditor.h"
#include "e2d/ui/State.h"
#include "e2d/ui/Utils.h"
#include "e2d/core/impl/components.h"
#include "e2d/core/Entity.h"

e2d::SceneTreeNodeEditor::SceneTreeNodeEditor()
	: fxcc::imgui::Layer("Scene Editor")
{

};

void e2d::SceneTreeNodeEditor::HandleSelection()
{
	ztclog::info("handleSelect ios");

	for (auto it : m_SelectedEntities)
	{
		it->m_Selected = false;
	}
	m_SelectedEntities.clear();

	for (auto it : m_Inst->m_EntityMap)
	{
		auto entity = it.second;

		entity->m_ImguiFlag;
		entity->m_Selected = false;

		if (ItemInSelectionRange(entity.get()))
		{
			bool hasParentAndParentRender = entity->m_Parent && entity->m_Parent->m_HasTreeNodedRender;
			bool noParent = (!entity->m_Parent);

			{
				entity->m_Selected = !entity->m_Selected;
				m_SelectedEntities.push_back(entity.get());
			}

		}
	}
};

void e2d::SceneTreeNodeEditor::HandlePaste()
{
	auto& sg = e2d::State::Inst();

	auto m_LastSelectedEntity = m_Inst->m_EditingEntity.m_Entity;
	if (m_LastSelectedEntity)
	{
		ztclog::info("Last edit entity %s", m_LastSelectedEntity->m_Name.c_str());
		
		// for (auto e : m_ClipboardEntities)
		// {
		// 	auto _p = e->SaveAsPrefebUUID();
		// 	auto e2 = m_Inst->NewEntityOnParent(0);
		// 	auto newUUID = e2->m_UUID;
			
		// 	e2d::Serializer serializer;
		// 	bool flag = serializer.DecodePath<e2d::Entity>(_p, *e2);
			
		// 	e2->m_UUID = newUUID;
		// 	m_LastSelectedEntity->SnatchEntityAsChild(e2);

		// 	sg.m_ReloadScene = true;
		// }
	}

}

void e2d::SceneTreeNodeEditor::HandleDelete()
{
	for (auto it : m_Inst->m_EntityMap)
	{
		auto entity = it.second;
		if (entity->m_Selected)
		{
			entity->m_Exist = false;
		}
	}
}
;

void e2d::SceneTreeNodeEditor::ViewFunc()
{
	if (!m_Inst)
	{
		return;
	}
	auto& sg = e2d::State::Inst();

	int index = 0;

	for (auto it : m_Inst->m_EntityMap)
	{
		it.second->m_HasTreeNodedRender = false;
	}

	auto m_LastSelectedEntity = m_Inst->m_EditingEntity.m_Entity;

	if (m_Editor.TreeNode("Info", m_Inst->m_ImguiFlag, index++))
	{
		m_Editor.EditInst<std::string>("name", m_Inst->m_Name);
		ImGui::Text("m_Entities %ld", m_Inst->m_Entities.size());
		ImGui::Text("m_AllEntitiesCalculated %ld", m_Inst->m_AllEntitiesCalculated.size());
		ImGui::Text("m_NumSelected entities %d", m_SelectedEntities.size());
		if (m_LastSelectedEntity)
		{
			ImGui::Text("Select entity %s", m_LastSelectedEntity->m_Name.c_str());

		}

		m_Editor.TreePop();
	}

	bool sceneTreeNode = m_Editor.TreeNode(m_Inst->m_Name, m_Inst->m_ImguiFlag, index++);

	if (ImGui::BeginDragDropTarget()) {
		if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("File")) {
			const fxcc::File receivedData = *(const fxcc::File*)payload->Data;
			ztclog::info("entity(%s) get a file relative %s", "nullptr", receivedData.m_RelativePath.c_str());

			PrefebImporter prefebImporter;
			PrefebLoader prefebLoader;
			auto _NewChild = prefebLoader.AddEntityToSceneNativePath(m_Inst.get(), 0, receivedData.m_RelativePath);

			if (_NewChild)
			{
				ztclog::info("add child %s", _NewChild->m_UUID.c_str(), _NewChild->m_Name.c_str());
				e2d::Utils::m_Inst.m_Scene->UploadEntityMap();
			}
		}
		ImGui::EndDragDropTarget();
	};

	if (ImGui::BeginDragDropTarget()) {
		if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("Entity")) {

			using T = std::shared_ptr<e2d::Entity>;
			const T receivedData = *(const T*)payload->Data;
			ztclog::info("Entity add to scene %s", receivedData->m_Name.c_str());
			m_Inst->SnatchEntityInstAsChild(receivedData);
		}
		ImGui::EndDragDropTarget();
	};


	if(sceneTreeNode)
	{
		for (auto entity: m_Inst->m_Entities)
		{
			this->TreeNodeEdit(entity);
		}
		m_Editor.TreePop();

	}


	if (ImGui::BeginPopupContextWindow())
	{
		if (ImGui::BeginMenu("New"))
		{
			if (ImGui::MenuItem("GameObject"))
			{
				auto newEntity = m_Inst->NewEntityOnParent(0);
				newEntity->m_Name = "gameObject";
				HandleAddNewEntity(newEntity);
			}
			if (ImGui::MenuItem("CameraView Edit"))
			{
				auto newEntity = m_Inst->NewEntityOnParent(0);
				newEntity->m_Name = "Camera View Edit";
				auto& cameraView = newEntity->GetOrEmplace<e2d::CameraViewEdit>();
				cameraView.OnLoad();
				HandleAddNewEntity(newEntity);
			}
			if (ImGui::MenuItem("CameraView"))
			{
				auto newEntity = m_Inst->NewEntityOnParent(0);
				newEntity->m_Name = "Camera View";
				auto& cameraView = newEntity->GetOrEmplace<e2d::CameraView>();
				cameraView.OnLoad();
				HandleAddNewEntity(newEntity);
			}
			// Magic menu
			//MagicMenu();

			ImGui::EndMenu();
		}
		if (ImGui::MenuItem("set all exist"))
		{
			m_Inst->SetAllExist();
		}
		ImGui::EndPopup();
	}

	ImGuiIO& io = ImGui::GetIO();

	if (m_IsFocused)
	{
		if (ImGui::IsKeyPressed(ImGuiKey_C) && io.KeyCtrl)
		{
			m_ClipboardEntities = m_SelectedEntities;
		}
		if (ImGui::IsKeyPressed(ImGuiKey_V) && io.KeyCtrl)
		{
			HandlePaste();
		}
		if (ImGui::IsKeyPressed(ImGuiKey_Delete))
		{
			HandleDelete();
		}

		if (!ImGui::IsAnyItemHovered() && ImGui::IsMouseClicked(ImGuiMouseButton_Left))
		{
			sg.m_ClearAllSelected = true;
		}
	}

}

void e2d::SceneTreeNodeEditor::HandleFunc()
{
	auto& sg = e2d::State::Inst();
	auto& io = ImGui::GetIO();


	if (sg.newEntity)
	{
		auto inst = m_Inst->NewEntityOnParent(0);
		sg.newEntity = false;

	}

	if (sg.selectEntityFlag)
	{
		m_Inst->m_EditingEntity =e2d::EntityMap(sg.selectedEntity);
		
		if (!sg.m_CtrlSelect)
		{
			for (auto e : m_SelectedEntities)
			{
				e->m_Selected = false;
			}
			m_SelectedEntities.clear();
			sg.selectedEntity->m_Selected = true;
			this->m_SelectedEntities.push_back(sg.selectedEntity);

		}
		else
		{
			ztclog::info("control selected");
			this->m_SelectedEntities.push_back(sg.selectedEntity);

			for (auto e : m_SelectedEntities)
			{
				e->m_Selected = true;
			}

		}
	
		sg.selectEntityFlag = false;

	}
	if (sg.m_ChangedSceneFlag)
	{
		this->m_Inst = sg.m_NewScene;
		sg.m_ChangedSceneFlag = false;
	}

	if (sg.m_ClearAllSelected)
	{
		for (auto e : m_SelectedEntities)
		{
			e->m_Selected = false;
		}
		m_SelectedEntities.clear();
		
		sg.m_ClearAllSelected = false;
	}

}

void e2d::SceneTreeNodeEditor::HandleAddNewEntity(std::shared_ptr<e2d::Entity> newEntity)
{
	auto m_LastSelectedEntity = m_Inst->m_EditingEntity.m_Entity;

	if (m_LastSelectedEntity)
	{
		newEntity->GetOrEmplace<e2d::TransformNode>();
		newEntity->GetOrEmplace<e2d::MonoScripts>();
		m_LastSelectedEntity->SnatchEntityAsChild(newEntity);
	}
	else
	{
		m_Inst->SnatchEntityInstAsChild(newEntity);
	}
	auto& sg = e2d::State::Inst();


}

bool e2d::SceneTreeNodeEditor::TreeNodeEdit(std::shared_ptr<e2d::Entity> e)
{
	auto& sg = e2d::State::Inst();

	ImGui::PushID(e.get());
	int index = 8;

	int flag = 0;

	if (e->m_Selected)
	{
		flag |= ImGuiTreeNodeFlags_Selected;
	};
	flag |= ImGuiTreeNodeFlags_OpenOnDoubleClick;

	e->m_HasTreeNodedRender = true;

	bool IsPrefeb{ 0 };

	bool hasPrefeb = e->HasComponent<e2d::Prefeb>();
	if (hasPrefeb)
	{
		const auto& prefebComponent = e->GetConst<e2d::Prefeb>();
		IsPrefeb = prefebComponent.m_SourceEntity.m_Entity;

	}
	
	if (IsPrefeb)
	{
		ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.5f, .5f, 1.0f, 1.0f)); 

	}
	std::string treeNodeLabel = e->m_Name;
	if (IsPrefeb)
	{
		treeNodeLabel += "(Prefeb)";
	}
	bool res = m_Editor.TreeNode(treeNodeLabel, e->m_ImguiFlag, index++, flag);
	
	if (IsPrefeb)
	{
		ImGui::PopStyleColor();
	}
	GetItemPos(e.get());

	if (ImGui::IsItemHovered() &&
		(ImGui::IsMouseReleased(ImGuiMouseButton_Left) || ImGui::IsMouseReleased(ImGuiMouseButton_Right))
		)
	{
		ztclog::info("Selected entity is %s %s", e->m_Name.c_str(), e->m_UUID.c_str());
		this->m_Inst->m_EditingEntity = e.get();

		sg.selectEntityFlag = true;
		sg.m_CtrlSelect = ImGui::GetIO().KeyCtrl;;
		//ztclog::info("ctrl %d", sg.m_CtrlSelect);
		sg.selectedEntity = e.get();
		sg.hireEntityFlag = true;

	}

	EditItemDragDrop(e);

	if (res)
	{
		for (auto it: e->m_Children)
		{
			TreeNodeEdit(it);
		}

		m_Editor.TreePop();
	}



	ImGui::PopID();
	return res;
}

void e2d::SceneTreeNodeEditor::EditItemDragDrop(std::shared_ptr<e2d::Entity> e)
{

	if (ImGui::BeginDragDropSource()) {

		using T = std::shared_ptr<e2d::Entity>;

		ImGui::SetDragDropPayload("Entity", &e, sizeof(T));
		ImGui::Text("Dragging %s", e->m_Name.c_str());
		ImGui::EndDragDropSource();
	}

	if (ImGui::BeginDragDropTarget()) {
		if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("Entity")) {

			using T = std::shared_ptr<e2d::Entity>;
			const T receivedData = *(const T*)payload->Data;

			e->SnatchEntityAsChild(receivedData);
		}
		ImGui::EndDragDropTarget();
	};

	auto& sg = e2d::State::Inst();

	if (ImGui::BeginDragDropTarget()) {
		if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("File")) {
			const fxcc::File receivedData = *(const fxcc::File*)payload->Data;
			ztclog::info("entity(%s) get a file relative %s", e->m_Name.c_str(), receivedData.m_RelativePath.c_str());

			PrefebLoader prefebLoader;
			auto _NewChild = prefebLoader.AddEntityToSceneNativePath(m_Inst.get(), e.get(), receivedData.m_RelativePath);

			if (_NewChild)
			{
				ztclog::info("add child %s", _NewChild->m_UUID.c_str(), _NewChild->m_Name.c_str());
			}

		}
		ImGui::EndDragDropTarget();
	};
}

